package org.lightpersist.util;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * 执行多个MethodInterceptor
 * @author GL
 *
 */
public class MethodInterceptorChain {
	private List<MethodInterceptor> interceptors;

	/**
	 * 
	 * @param interceptors
	 */
	public MethodInterceptorChain(List<MethodInterceptor> interceptors) {
		super();
		this.interceptors = interceptors;
	}

	/**
	 * 
	 * @param interceptors
	 */
	public MethodInterceptorChain(MethodInterceptor...interceptors){
		this.interceptors = new ArrayList<MethodInterceptor>();
		for(MethodInterceptor interceptor:interceptors){
			this.interceptors.add(interceptor);
		}
	}
	
	/**
	 * 执行方法，将依次调用MethodInterceptor，至拦截器末尾将执行原始方法
	 * @param object
	 * @param method
	 * @param args
	 * @return
	 * @throws Throwable 
	 */
	public Object invoke(final Object object,final Method method,final Object[] args) throws Throwable{
		return invoke(object, method, args, true);
	}
	
	/**
	 * 执行方法，将依次调用MethodInterceptor，至拦截器末尾根据invokeRaw参数决定是否执行原始方法
	 * @param object
	 * @param method
	 * @param args
	 * @param invokeRaw  执行原始方法
	 * @return
	 * @throws Throwable
	 */
	public Object invoke(final Object object,final Method method,final Object[] args,final boolean invokeRaw) throws Throwable{
		return invoke(new MethodInvocation(){

			public Method getMethod() {
				return method;
			}

			public Object[] getArguments() {
				return args;
			}

			public AccessibleObject getStaticPart() {
				return method;
			}

			public Object getThis() {
				return object;
			}

			public Object proceed() throws Throwable {
				return getMethod().invoke(getThis(), getArguments());
			}
			
		},invokeRaw);
	}
	
	/**
	 * 执行方法，将依次调用MethodInterceptor，至拦截器末尾将执行原始方法
	 * @param invocation
	 * @return
	 * @throws Throwable
	 */
	public Object invoke(MethodInvocation invocation) throws Throwable{
		return invoke(invocation, true);
	}
	
	/**
	 * 执行方法，将依次调用MethodInterceptor，至拦截器末尾根据invokeRaw参数决定是否执行原始方法
	 * @param invocation
	 * @param invokeRaw 是否执行原始方法
	 * @return
	 * @throws Throwable
	 */
	public Object invoke(MethodInvocation invocation,boolean invokeRaw) throws Throwable{
		return new MethodInvocationChain(invocation,interceptors.iterator(),invokeRaw).proceed();
	}
	
	private static class MethodInvocationChain implements MethodInvocation{
		final Iterator<MethodInterceptor> iterator;
		final MethodInvocation raw;
		final boolean invokeRaw;
		public MethodInvocationChain(MethodInvocation invocation,Iterator<MethodInterceptor> iterator, boolean invokeRaw) {
			this.raw = invocation;
			this.iterator = iterator;
			this.invokeRaw = invokeRaw;
		}

		public Method getMethod() {
			return raw.getMethod();
		}

		public Object[] getArguments() {
			return raw.getArguments();
		}

		public AccessibleObject getStaticPart() {
			return raw.getStaticPart();
		}

		public Object getThis() {
			return raw.getThis();
		}

		public Object proceed() throws Throwable {
			if(iterator.hasNext()){
				MethodInterceptor interceptor = iterator.next();
				return interceptor.invoke(this);
			}
			if(invokeRaw)
				return raw.proceed();
			return null;
		}
		
	}
}
